home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / Modes / stataMode.tcl < prev    next >
Encoding:
Text File  |  2001-01-26  |  69.7 KB  |  2,044 lines

  1. ## -*-Tcl-*-  (nowrap)
  2.  # ==========================================================================
  3.  #  Statistical Modes - an extension package for Alpha
  4.  # 
  5.  #  FILE: "stataMode.tcl"
  6.  #                                    created: 01/15/00 {07:15:32 pm} 
  7.  #                                last update: 01/26/01 {12:08:23 pm} 
  8.  #  Description: 
  9.  # 
  10.  #  For Stata "do" and output files.
  11.  #  
  12.  #  Author: Craig Barton Upright
  13.  #  E-mail: <cupright@princeton.edu>
  14.  #    mail: Princeton University,  Department of Sociology
  15.  #          Princeton, New Jersey  08544
  16.  #     www: <http://www.princeton.edu/~cupright>
  17.  #  
  18.  #  Stata menu written, maintained by L. Phillip Schumm <pschumm@uchicago.edu> 
  19.  #  
  20.  # -------------------------------------------------------------------
  21.  #  
  22.  # Copyright (c) 2000-2001  Craig Barton Upright, L. Phillip Schumm
  23.  # 
  24.  # This program is free software; you can redistribute it and/or modify
  25.  # it under the terms of the GNU General Public License as published by
  26.  # the Free Software Foundation; either version 2 of the License, or
  27.  # (at your option) any later version.
  28.  # 
  29.  # This program is distributed in the hope that it will be useful,
  30.  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  31.  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  32.  # GNU General Public License for more details.
  33.  # 
  34.  # You should have received a copy of the GNU General Public License
  35.  # along with this program; if not, write to the Free Software
  36.  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  37.  # 
  38.  # ==========================================================================
  39.  ##
  40.  
  41. # ===========================================================================
  42. # ◊◊◊◊ Initialization of Stta mode ◊◊◊◊ #
  43.  
  44. alpha::mode Stta 2.1.1 stataMenu {*.do *.ado} {
  45.     stataMenu electricReturn electricSemicolon electricTab electricBraces
  46. } {
  47.     # We require 7.4b21 for prefs handling.
  48.     alpha::package require -loose AlphaTcl 7.4b21
  49.     addMenu stataMenu "•155" Stta
  50.     set unixMode(stata) {Stta}
  51.     set modeCreator(S5x8) {Stta}
  52. } uninstall {
  53.     catch {file delete [file join $HOME Tcl Modes stataMode.tcl]}
  54.     catch {file delete [file join $HOME Tcl Completions SttaCompletions.tcl]}
  55.     catch {file delete [file join $HOME Tcl Completions "Stta Tutorial.do"]}
  56. } help {
  57.     file "Statistical Modes Help"
  58. } maintainer {
  59.     "Craig Barton Upright" <cupright@princeton.edu> 
  60.     <http://www.princeton.edu/~cupright/>
  61. }
  62.  
  63. hook::register quitHook Stta::quitHook
  64.  
  65. proc stataMenu {} {}
  66.  
  67. proc stataMode.tcl {} {}
  68.  
  69. namespace eval Stta {}
  70.  
  71. # ===========================================================================
  72. # ◊◊◊◊  Stta mode variables ◊◊◊◊ #
  73. #
  74.  
  75. # Removing obsolete preferences from earlier versions.
  76.  
  77. set oldvars {
  78.     abbrevColor addAbbreviations addArguments addFunctions addMacros
  79.     addModifiers addParameters argumentColor codebookSuffix datedColor
  80.     delimiter don'tRemindMe electricTab functionColor keywordColor
  81.     localHelpOnly parameterColor macroColor modifierColor stataHelp
  82. }
  83.  
  84. foreach oldvar $oldvars {prefs::removeObsolete SttamodeVars($oldvar)}
  85.  
  86. unset oldvar oldvars
  87.  
  88. # ===========================================================================
  89. #
  90. # Standard preferences recognized by various Alpha procs
  91. #
  92.  
  93. newPref var  fillColumn         {75}                    Stta
  94. newPref var  leftFillColumn     {0}                     Stta
  95. newPref var  prefixString       {* }                    Stta
  96. newPref var  wordBreak          {[-a-zA-Z0-9\._\#]+}    Stta
  97. newPref var  wordBreakPreface   {[^-a-zA-Z0-9\._\#]}    Stta
  98. newPref flag wordWrap           {0}                     Stta
  99.  
  100. # ===========================================================================
  101. #
  102. # Flag preferences
  103. #
  104.  
  105. newPref flag autoMark           {0}     Stta    {Stta::rebuildMenu markStataFileAs}
  106.  
  107. # Indent all continued commands, indicated by "/*" at the end of a command
  108. # line, or by the lack of a semi-colon if the "Semi Delimiter" preference
  109. # is set, by the full indentation amount rather than half.
  110. newPref flag fullIndent         {1}     Stta    {Stta::rebuildMenu markStataFileAs}
  111.  
  112. # Check this box if to use semicolons as a delimiter in do files.  This
  113. # will be used in all electric completions.
  114. newPref flag semiDelimiter      {0}     Stta    {Stta::rebuildMenu stataHelp}
  115.  
  116. # By default command double-click will send a command to on-line help, and
  117. # option double-click sends a command to the local Stata application. 
  118. # Check this box to switch these key combinations.
  119. newPref flag localHelp          {0}     Stta    {Stta::rebuildMenu stataHelp}
  120.  
  121. # Check this box if your keyboard does not have a "Help" key.  This will
  122. # change some of the menu's key bindings.
  123. newPref flag noHelpKey          {0}     Stta    {Stta::rebuildMenu stataHelp}
  124.  
  125. # Set the list of flag preferences which can be changed in the menu.
  126.  
  127. set SttaPrefsInMenu [list       \
  128.   "localHelp"                   \
  129.   "noHelpKey"                   \
  130.   "semiDelimiter"               \
  131.   "fullIndent"                  \
  132.   ]
  133.  
  134. # ===========================================================================
  135. #
  136. # Variable preferences
  137.  
  138. # Enter additional Stata commands  or abbreviations to be colorized.
  139. newPref var addCommands         {}      Stta    {Stta::colorizeStta}
  140.  
  141. # Enter additional options or abbreviations to be colorized.  
  142. newPref var addOptions          {gen rep}       Stta    {Stta::colorizeStta}
  143.  
  144. # Command double-clicking on a Stata keyword will send it to this url for a
  145. # help reference page.
  146. newPref url helpUrl             {http://www.stata.com/help.cgi?}        Stta
  147.  
  148. # The "Stata Home Page" menu item will send this url to your browser.
  149. newPref url stataHomePage       {http://www.stata.com/} Stta
  150.  
  151. # Click on "Set" to find the local Stata application.
  152. newPref sig stataSig            {S5x8}  Stta
  153.  
  154. # ===========================================================================
  155. # Color preferences
  156. #
  157. # Nomenclature notes:
  158. # Stata has five levels of processes.
  159. #   1. "commands", "subcommands", "prefixes":  describe, define, quietly, 
  160. #   2. "parameters": textsize, maxobs, prefix, more,
  161. #   3. "functions": abs(), log(), sin(), ge, lt,
  162. #   4. "options": saving(), naxis graph, matrix graph,
  163. #   5. "modifiers": [weights= ], [frequency= ]
  164. #  and, just to help make sure that everything goes smoothly, we have
  165. #  
  166. #   6. out of date (or "dated") commands:  genrank, grebar
  167. #   
  168. # For the most part, Stata is very good about not using the same name for a
  169. # command to refer to a function, parameter, or modifier.  Options,
  170. # however, often have the same names as commands.
  171. # The default setup of this mode is to colorize all of commands,
  172. # subcommands, prefixes, parameters, and macros blue.  Options, functions,
  173. # modifiers, and symbols are colorized magenta.  Dated commands are red. 
  174. # The user does not have to specify all of these different levels -- only
  175. # Command, Comment, Option, String, and Symbol colors appear in the
  176. # preferences.
  177. # In addition, non-ambiguous abbreviations of command names are allowed. 
  178. # They could be entered as Additional Commands or Additional Options
  179. # through Config -- > Mode --> Mode Preferences.
  180. # The sections which follow are based on release 3.1 of Stata, because that
  181. # was the latest full manual that I could get my hands on ...
  182. #
  183.  
  184. # See the Statistical Modes Help file for an explanation of these different
  185. # categories, and lists of keywords.
  186. newPref color commandColor      {blue}      Stta    {Stta::colorizeStta}
  187. newPref color commentColor      {red}       Stta    {stringColorProc}
  188. newPref color optionColor       {magenta}   Stta    {Stta::colorizeStta}
  189. newPref color stringColor       {green}     Stta    {stringColorProc}
  190.  
  191. # The color of symbols such as "+", "-", etc.
  192. newPref color symbolColor       {magenta}   Stta    {Stta::colorizeStta}
  193.  
  194. regModeKeywords -e {*} -b {/*} {*/}     \
  195.   -c $SttamodeVars(commentColor)        \
  196.   -s $SttamodeVars(stringColor) Stta {}
  197.  
  198. # ==========================================================================
  199. # Comment Character variables for Comment Line / Paragraph / Box menu items.
  200.  
  201. set Stta::commentCharacters(General)    "* "
  202. set Stta::commentCharacters(Paragraph)  [list "/* " " */" " * "]
  203. set Stta::commentCharacters(Box)        [list "/*" 2 "*/" 2 "*" 3]
  204.  
  205. # The Comment Line command is hard-wired -- except for the C and C++ modes,
  206. # if the commentCharacters(Paragraph) are different, then Comment Line will
  207. # automatically be bracketed.  Thus I am simply redefining the command-d
  208. # key-binding to ignore commentLine
  209.  
  210. Bind 'd' <c>  {insertPrefix} Stta
  211.  
  212. # ===========================================================================
  213. # Flag Flip
  214. # Called by menu items, change the value of flag preferences.
  215.  
  216. proc Stta::flagFlip {pref} {
  217.  
  218.     global mode SttamodeVars
  219.  
  220.     set SttamodeVars($pref) [expr {$SttamodeVars($pref) ? 0 : 1}]
  221.     set oldMode $mode
  222.     set mode "Stta"
  223.     synchroniseModeVar $pref $SttamodeVars($pref)
  224.     set mode $oldMode
  225.     if {$SttamodeVars($pref)} {
  226.         set end "on"
  227.     } else {
  228.         set end "off"        
  229.     } 
  230.     message "The \"$pref\" preference is now $end."
  231. }
  232.  
  233. # ===========================================================================
  234. # ◊◊◊◊ Keyword Dictionaries ◊◊◊◊ #
  235. #
  236.  
  237. # Making sure that SttaUserCommands and SttaUserOptions exist.
  238. # These will be over-ridden if they are loaded from a ${mode}Prefs.tcl file.
  239. #
  240.  
  241. set SttaUserCommands    ""
  242. set SttaUserOptions     ""
  243.  
  244. # ===========================================================================
  245. # ◊◊◊◊   Stta Commands   ◊◊◊◊ #
  246. #
  247. # this also includes a select few unix shell commands
  248. #
  249.  
  250. set SttaCommands { 
  251.     STATA _qreg _robust accum acprplot adopath alpha anova aorder append
  252.     areg assert auto.dta avplot avplots bcskew0 begin bitest bitesti blogit
  253.     bmemsize boxcox bprobit brier bs bsample bsqreg bstat bstrap canon cc
  254.     cchart cci cd centile cf ci cii clear clogit cmdtool cnreg cnsreg
  255.     codebook coleq collapse colnames compare compress confirm constraint
  256.     convert correlate count cox cprplot cross cs csi cumul cusum decode
  257.     define degph delimit depnames describe dfbeta dictionary dir discard
  258.     dispCns display do dprobit drop ds dydx echo egen eivreg else encode
  259.     end erase ereg error existence exit expand factor fillin for format fsl
  260.     function generate gladder global glogit glsaccum gnbreg gphdot gphpen
  261.     gprobit graph greigen grmeanby groups gunzip gzip hadimvo heckman help
  262.     hilite hold hotel if impute infile input inspect integ intreg ipolate
  263.     iqreg ir iri kap kappa kapwgt keep ksm ksmirnov ktau kwallis ladder
  264.     lfit linktest list lnskew0 local log logistic logit loneway lookfor
  265.     lroc lrtest ls lstat ltable lv lvr2plot makeCns man matcproc maximize
  266.     mcc mcci means memsize menu merge method mhodds mlogit mlout model move
  267.     mvdecode mvencode mvreg mx_param nbreg nl nlinit nptrend ologit oprobit
  268.     order outfile outsheet pause pchart pchi pcorr pd pd.X pd.ix pd.sunview
  269.     pd.wy99 plot pnorm poisson post postclose postfile predict preserve
  270.     probit profile.do pwcorr pwd qchi qnorm qqplot qreg quantile query
  271.     range ranksum rchart recast recode regph regress rename renpfix replace
  272.     report restore review rm rotate roweq rownames rreg run runtest rvfplot
  273.     rvpplot sample save score sdtest sdtesti search serrbar sfrancia shell
  274.     shewhart signrank signtest sktest smooth sort spearman sqreg stack stem
  275.     substitute summarize sureg svd swilk symeigen symplot sysdir tab1 tab2
  276.     tabi tabodds tabulate tempfile tempname tempvar testparm tobit touch
  277.     ttest ttesti type uncompress unhold use vars vecaccum verinst version
  278.     weibull which while window xchart xpose
  279. }
  280.  
  281. # ===========================================================================
  282. # ◊◊◊◊   Prefixes   ◊◊◊◊ #
  283.  
  284. # This includes not only prefixes proper {capture, noisily, quietly}, but
  285. # also commands that are only part of command-phrases.  These are
  286. # distinguished from SttaCommands for the Stta::Completions::Commands proc.
  287. #
  288.  
  289. set SttaPrefixes {
  290.     capture constraint eq estimates label macro matrix ml noisily program
  291.     quietly reshape scalar set window xi:
  292. }
  293.  
  294. # ===========================================================================
  295. # ◊◊◊◊   Parameters   ◊◊◊◊ #
  296. #
  297.  
  298. set SttaParameters {
  299.     adosize ANSI beep contents graphics IBM level linesize matsize maxobs
  300.     maxvar memory more obs output pagesize prefix rmsg seed textsize trace
  301.     video virtual width
  302. }
  303.  
  304. # ===========================================================================
  305. # ◊◊◊◊   Functions   ◊◊◊◊ #
  306. #
  307.  
  308. set SttaFunctions {
  309.     abs atan autocode Binomial chiprob comma condcos diff exp float fprob
  310.     gammap ge get group gt ibeta index int invbimonial invnorm invt iqr le
  311.     length ln lngamma lower lt ltrim ma max mean median mod min norprob
  312.     pctile rawsum real rank round rmean rmiss robs rtrim rsum sd sign sin
  313.     sqrt string std substr sum thru tprob trim uniform upper
  314. }
  315.  
  316. # ===========================================================================
  317. # ◊◊◊◊   Options  ◊◊◊◊ #
  318. #
  319.  
  320. set SttaOptions {
  321.     ..  Rescale V accumulate accuracy adjust all alt asif b1title b2title
  322.     backward bands bar bartlett basecategory beta bin bonferroni border box
  323.     bsize bwidth cell censored chi2 column connect constraints continuity
  324.     cooksd corr covariance cutoff ddeviance dead delta density depname depv
  325.     detail deviance df dof dx2 eform eps equal equation exact exposure
  326.     factors failure fcnlabel fenter forward from fstay gamma gap genwt get
  327.     group half hascons hat hazard histogram hlines horst hr i incr init
  328.     initial intervals ipf irr iterate jitter l1title l2title leave lf0
  329.     limits line lines lnlsq lnnormal lock lower lowess lrchi2 ltolerance
  330.     margin mineigen missing mse1 noadjust noalt noanova noauto noaxis
  331.     noborder nocoef nocone noconf nocons noconstant nodetail noformat
  332.     nofreq nograph noheader nolabel nolog nomeans noobs norotate nostandard
  333.     notab notable notest noties noweight number oneway or outcome pc pcd pe
  334.     pen pie pr pr2 promax protect psize r1title r2title random rbox reps
  335.     rescale resid residuals rlabel rlog root rrr rscale rstandard rstudent
  336.     rtick rules scheffe select shading sidak split stabilzied star stdf
  337.     stdp stdr strata symbol symbolic t1title t2title taub threshold title
  338.     tlabel tolerance total tr trim ttick tune tvid twoway unequal unpaired
  339.     upper varimax varp vlines vwidth wgt wide wlsiter wrap xb xlabel xlog
  340.     xscale xtick ylabel ylog yscale ytick zero
  341. }
  342.     
  343.  
  344. # ===========================================================================
  345. # ◊◊◊◊   Modifiers   ◊◊◊◊ #
  346. #
  347.  
  348. set SttaModifiers {
  349.     .do .dot .dta .gph .help .log .pen .raw .xp TEMP _N _all _b _coef
  350.     _merge _n _pi _rc _se aweight by fast frequency fweight in iweight
  351.     ltolerance off old on pddefs pweight saving stata.do stata.hlp
  352.     stata.lic stata.mnu stata.usr statpd title using value values variable
  353.     variables weight
  354. }
  355.  
  356. # ===========================================================================
  357. # ◊◊◊◊   Stata Macros   ◊◊◊◊ #
  358. #
  359.  
  360. set SttaMacros {
  361.     S_ADO A_DATE S_E_ S_E_11 S_mdf S_nobs S_E_tdf S_FLAVOR S_FN
  362.     S_MACHID S_mldbug S_MODE S_NOFKEY S_OS S_OSDTL S_TIME
  363. }
  364.  
  365. # ===========================================================================
  366. # ◊◊◊◊   Dated Commands   ◊◊◊◊ #
  367. #
  368.  
  369. set SttaDated {
  370.     _huber boot bootsamp chdir clogitp corc coxbase coxhaz coxvar datetof
  371.     dbeta deff disp_res disp_s etodow etof etomdy fit fpredict ftodate ftoe
  372.     ftomdy ftowdate genrank genstd genvmean glmpred grebar gwood hareg
  373.     hereg hlogit hlu hprobit hreg huber kapmeier leverage logiodds
  374.     logiodds2 loglogs logrank lpredict mantel mdytoe mdytof modify nlpred
  375.     ologitp oprobitp parse regdw remap repeat stepwise survcurv survival
  376.     survsum swcnreg swcox swereg swlogis swlogit swologit swoprbt swpois
  377.     swprobit swqreg swtobit swweib textstd wdatetof wilcoxon xtpred
  378. }
  379.  
  380. #==============================================================================# 
  381. # Colorize Stta
  382. # Set all keyword lists, and colorize.
  383. # Could also be called in a <mode>Prefs.tcl file
  384.  
  385. proc Stta::colorizeStta {{pref ""}} {
  386.     
  387.     global SttamodeVars  SttaCommands SttaPrefixes     SttaParameters  
  388.     global SttaFunctions SttaOptions  SttaModifiers    SttaMacros         
  389.     global SttaDated     SttaUserCommands SttaUserOptions
  390.     
  391.     global SttaCommandList SttaOptionList Sttacmds
  392.  
  393.     # First setting aside only the commands, for Stta::Completion::Command.
  394.     set SttaCommandList [concat                                 \
  395.       $SttaCommands $SttaPrefixes $SttamodeVars(addCommands)    \
  396.       $SttaUserCommands $SttaParameters                         \
  397.       ]
  398.  
  399.     # Then setting aside only the options, for Sttaelectric().
  400.     set SttaOptionList [concat                                  \
  401.       $SttaOptions $SttamodeVars(addOptions) $SttaUserOptions   \
  402.       ]
  403.  
  404.     # Then, create the list of all keywords for completions.
  405.     set Sttacmds [lsort [concat                                 \
  406.       $SttaCommandList $SttaOptionList $SttaFunctions           \
  407.       $SttaModifiers $SttaDated                                 \
  408.       ]]
  409.  
  410.     # Commands, Prefixes, Parameters, User Macros
  411.     regModeKeywords -a                          \
  412.       -k $SttamodeVars(commandColor) Stta $SttaCommandList
  413.     
  414.     # Functions, Options, Modifiers, Stata-Macros, 
  415.     regModeKeywords -a                          \
  416.       -k $SttamodeVars(optionColor) Stta        \
  417.       [concat $SttaOptionList $SttaFunctions    \
  418.       $SttaParameters $SttaModifiers $SttaMacros ]
  419.     
  420.     # Dated
  421.     regModeKeywords -a                          \
  422.       -k red Stta $SttaDated 
  423.     
  424.     # Symbols
  425.     regModeKeywords -a                          \
  426.       -k $SttamodeVars(symbolColor) Stta {|}    \
  427.       -i "+" -i "-" -i "_" -i "\\"              \
  428.       -I $SttamodeVars(symbolColor) 
  429.     
  430.     if {$pref != ""} {refresh}
  431. }
  432.  
  433. # Call this now.
  434.  
  435. Stta::colorizeStta
  436.  
  437. # ===========================================================================
  438. #
  439. # Reload Completions.  
  440. # This is now an obsolete proc.
  441.  
  442. proc Stta::reloadCompletions {} {
  443.     alertnote "\"Stta::reloadCompletions\" is an obsolete proc.\
  444.       It should be removed from your SttaPrefs.tcl file."
  445. }
  446.  
  447. # ===========================================================================
  448. #
  449. # ◊◊◊◊ Key Bindings, Electrics ◊◊◊◊ #
  450. # abbreviations:  <o> = option, <z> = control, <s> = shift, <c> = command
  451.  
  452. # Known bug: Key-bindings from other global menus might conflict with those
  453. # defined in the Stata menu.  This will help ensure that this doesn't happen.
  454.  
  455. Bind 's'    <cs>    {Stta::switchToStata} Stta
  456. Bind 'd'    <cs>    {Stta::doFile} Stta
  457. Bind 'd'    <csz>   {Stta::doSelection} Stta
  458. Bind 'p'    <cs>    {Stta::insertPath} Stta
  459. Bind 'p'    <csz>   {Stta::programTamplate} Stta
  460.  
  461. Bind '\;'   <sz>    {Stta::helpProc stataHelp semiDelimiter} Stta
  462. Bind ':'    <sz>    {Stta::helpProc stataHelp semiDelimiter} Stta
  463.  
  464. Bind 'n'    <sz>    {Stta::nextCommand} Stta
  465. Bind 'p'    <sz>    {Stta::prevCommand} Stta
  466. Bind 's'    <sz>    {Stta::selectCommand} Stta
  467. Bind 'c'    <sz>    {Stta::copyCommand} Stta
  468.  
  469. Bind 'i'    <cz>    {Stta::reformatCommand} Stta
  470.  
  471. Bind '\r'   <s>     {Stta::continueCommand} Stta
  472. Bind '\)'           {Stta::electricRight "\)"} Stta
  473.  
  474. # For those that would rather use arrow keys to navigate.  Up and down
  475. # arrow keys will advance to next/prev command, right and left will also
  476. # set the cursor to the top of the window.
  477.  
  478. Bind    up  <sz>    {Stta::prevCommand 0 0} Stta
  479. Bind  left  <sz>    {Stta::prevCommand 0 1} Stta
  480. Bind  down  <sz>    {Stta::nextCommand 0 0} Stta
  481. Bind right  <sz>    {Stta::nextCommand 0 1} Stta
  482.  
  483. # ===========================================================================
  484. # Stta Carriage Return
  485. # Inserts a carriage return, and indents properly.
  486.  
  487. proc Stta::carriageReturn {} {
  488.     
  489.     global SttamodeVars
  490.     
  491.     if {[isSelection]} {deleteSelection} 
  492.     
  493.     set pos1 [lineStart [getPos]]
  494.     set pos2 [getPos]
  495.     if {[regexp {^([\t ])*(end|\}|\))} [getText $pos1 $pos2]]} {
  496.         createTMark temp $pos2
  497.         catch {bind::IndentLine}
  498.         gotoTMark temp ; removeTMark temp
  499.     } 
  500.     insertText "\r"
  501.     catch {bind::IndentLine}
  502. }
  503.  
  504. # ===========================================================================
  505. # Stta Electric Semi
  506. # Inserts a semi, carriage return, and indents properly.
  507.  
  508. proc Stta::electricSemi {} {
  509.     
  510.     global SttamodeVars 
  511.     
  512.     if {[isSelection]} {
  513.         deleteSelection
  514.     } 
  515.     if {[literalChar] || !$SttamodeVars(semiDelimiter)} {
  516.         typeText {;}
  517.         return
  518.     }
  519.     set pos1 [lineStart [getPos]]
  520.     set pos2 [getPos]
  521.     insertText {;}
  522.     bind::CarriageReturn
  523. }
  524.  
  525. # ===========================================================================
  526. #
  527. # Stta Electric Left, Right
  528. # Adapted from "tclMode.tcl"
  529.  
  530. proc Stta::electricLeft {} {
  531.  
  532.     if {[literalChar]} {
  533.         typeText "\{"
  534.         return
  535.     }
  536.     set pat "\}\[ \t\r\n\]*(else(if)?)\[ \t\r\n\]*\$"
  537.     set pos [getPos]
  538.     if { [set result [findPatJustBefore "\}" $pat $pos word]] == "" } { 
  539.         insertText "\{"
  540.         return
  541.     }
  542.     # we have an if/else(if)/else
  543.     switch -- $word {
  544.         "else" {
  545.             deleteText [lindex $result 0] $pos
  546.             elec::Insertion "\} $word \{\r\t••\r\}\r••"
  547.         }
  548.         "elseif" {
  549.             deleteText [lindex $result 0] $pos
  550.             elec::Insertion "\} $word \{••\} \{\r\t••\r\}\r••"
  551.         }
  552.     }
  553. }
  554.     
  555. proc Stta::electricRight {{char "\}"}} {
  556.     
  557.     if {[literalChar]} {
  558.         typeText $char
  559.         return
  560.     }
  561.     set pos [getPos]
  562.     typeText $char
  563.     if {![regexp {[^ \t]} [getText [lineStart $pos] $pos]]} {
  564.         set pos [lineStart $pos]
  565.         createTMark temp [getPos]
  566.         catch {bind::IndentLine}
  567.         gotoTMark temp ; removeTMark temp
  568.         bind::CarriageReturn
  569.     } 
  570.     if {[catch {blink [matchIt $char [pos::math $pos - 1]]}]} {
  571.         beep ; message "No matching $char !!"
  572.     } 
  573. }
  574.  
  575. # ===========================================================================
  576. #
  577. # Continue Command
  578. # Indenting continuation lines relative to start of command.
  579.  
  580. proc Stta::continueCommand {} {
  581.  
  582.     set thisLine [lindex [Stta::getCommandLine [lineStart [getPos]] 1 0] 2]
  583.     set thisLine [string trim $thisLine]
  584.     if {![regexp {/\*([^\*]*)$} $thisLine]} {
  585.         typeText " /*"
  586.     } 
  587.     Stta::carriageReturn
  588.     insertText "*/ "
  589. }
  590.  
  591. # This was the old proc, which didn't have Stta::indentLine available.
  592. # Indenting continuation lines by one space relative to start of command. 
  593. # (Note: Inserting space at first was the only way I was able to get this
  594. # to work when at the end of the last line of a file.  -- lps)
  595.  
  596. # proc Stta::continueCommand {} {
  597. #     insertText " "
  598. #     backwardChar
  599. #     set begHere [search -s -f 0 -r 1 -i 0 {^[ \t]*[^ (\*\/)\t\r\n]} [getPos]]
  600. #     set indAmt [getText [lindex $begHere 0] [pos::math [lindex $begHere 1] -1]]
  601. #     insertText " /*\r$indAmt */"
  602. #     forwardChar
  603. # }
  604.  
  605. # ===========================================================================
  606. #
  607. # ◊◊◊◊ Indentation ◊◊◊◊ #
  608. # Stta::correctIndentation is necessary for Smart Paste, and returns the
  609. # correct level of indentation for the current line.  Stta::indentLine uses
  610. # this level to indent the current line.
  611. # We have three levels of indentation in Stata.  The first is for the
  612. # continuation of commands, in which case we simply indent respecting the
  613. # Stta mode variable fullIndent.  The second is for programs, in which case
  614. # we indent the start of each command by indentationAmount until we reach
  615. # an "end" command.  The third is for nested {} statements.
  616. # In Stta::correctIndentation, we grab the previous line, remove all of the
  617. # characters besides braces and quotes, and then convert it all to a list
  618. # to be evaluated.  Braces contained within quotes, as well as literal
  619. # characters, should all be ignored and the remaining braces are used to
  620. # determine the correct level of nesting.
  621. # This works really well for "simple" syntax files, without multi-line
  622. # block commented sections embedded in either program definitions or actual
  623. # commands.
  624. # Known limitation (or a feature, depending on your point of view):
  625. # Indented lines of block comments will be recognized as "valid"
  626. # commands that are being continued, and themselves indented when a region
  627. # is formatted, leading to a construction that looks like this:
  628. #       command var
  629. #       
  630. #       /* 
  631. #           * It is important to note that the CPS files produced
  632. #           * by the Census Bureau do not have decimal points in
  633. #           * the data.  
  634. #           */
  635. #        
  636. #       next command var
  637. # or maybe
  638. #       command var
  639. #       
  640. #       /*  It is left to the documentation to inform
  641. #           the user how many decimals are implied.  The user
  642. #           must make the proper adjustment before using
  643. #           weights.  This is true for all the weights. 
  644. #           */
  645. # In this case, it's important that the ending */ appear on a line by
  646. # itself to signal that this line was a "continued" command, now complete. 
  647. # It all gets messier when trying to figure out what a syntax file "should"
  648. # look like given the semi delimiter possibility, too ...
  649.  
  650. proc Stta::indentLine {{pos ""}} {
  651.     
  652.     if {$pos == ""} {set pos [getPos]} 
  653.     # Get details of current line.
  654.     set posBeg [lineStart [getPos]]
  655.     set text [getText $posBeg [nextLineStart $posBeg]]
  656.     regexp {^[ \t]*} $text white 
  657.     set posNext1 [pos::math $posBeg + [string length $white]]
  658.     set posNext2 [pos::math $posNext1 + 1]
  659.     if {[pos::compare $posNext2 > [maxPos]]} {
  660.         set posNext2 [maxPos]
  661.     } 
  662.     # Determine the correct level of indentation for this line, given the
  663.     # next character.
  664.     set lwhite [Stta::correctIndentation $pos [getText $posNext1 $posNext2]]
  665.     set lwhite [text::indentOf $lwhite]
  666.     if {$white != $lwhite} {
  667.         replaceText $posBeg $posNext1 $lwhite
  668.     }
  669.     goto [pos::math $posBeg + [string length $lwhite]]
  670. }
  671.  
  672. proc Stta::correctIndentation {pos {next ""}} {
  673.     
  674.     global mode indent_amounts SttamodeVars
  675.     
  676.     if {$mode == "Stta"} {
  677.         set continueIndent [expr {$SttamodeVars(fullIndent) + 1}]
  678.     } else {
  679.         set continueIndent 2
  680.     } 
  681.     
  682.     set posBeg   [lineStart $pos]
  683.     # Get information about this line, previous line ...
  684.     set thisLine  [Stta::getCommandLine $posBeg 1 2]
  685.     set prevLine1 [Stta::getCommandLine [pos::math $posBeg - 1] 0 2]
  686.     set prevLine2 [Stta::getCommandLine [pos::math [lindex $prevLine1 0] - 1] 0 2]
  687.     set lwhite    [lindex $prevLine1 1]
  688.     # If we have a previous line ...
  689.     if {[pos::compare [lindex $prevLine1 0] != $posBeg]} {
  690.         set pL1 [string trim [lindex $prevLine1 2]]
  691.         # Indent if the preceding command was a program definition.
  692.         if {[regexp {^[\t ]*program+[\t ]+define} $pL1]} {
  693.             incr lwhite $indent_amounts(2)
  694.         } 
  695.         # Indent if the last line did not terminate the command.
  696.         if {![Stta::endOfCommand $pL1]} {
  697.             incr lwhite $indent_amounts($continueIndent)
  698.         } 
  699.         # Check to make sure that the previous command was not itself a
  700.         # continuation of the line before it.
  701.         if {[pos::compare [lindex $prevLine1 0] != [lindex $prevLine2 0]]} {
  702.             set pL2 [string trim [lindex $prevLine2 2]]
  703.             if {![Stta::endOfCommand $pL2]} {
  704.                 incr lwhite $indent_amounts(-$continueIndent)
  705.             } 
  706.         }
  707.         # Find out if there are any unbalanced {,},(,) in the last line.
  708.         regsub -all {[^ \{\}\(\)\"\*\/\\]} $pL1 { } line
  709.         # Remove all literals.
  710.         regsub -all {\\\{|\\\}|\\\(|\\\)|\\\"|\\\*|\\\/} $line { } line
  711.         regsub -all {\\} $line { } line
  712.         # Remove everything surrounded by quotes.
  713.         regsub -all {\"([^\"]+)\"} $line { } line
  714.         regsub -all {\"} $line { } line
  715.         # Remove everything surrounded by bracketed comments.
  716.         regsub -all {/\*([^\*/]+)\*/} $line { } line
  717.         # Now turn all braces into 2's and -2's
  718.         regsub -all {\{|\(} $line { 2 }  line
  719.         regsub -all {\}|\)} $line { -2 } line
  720.         # This list should now only contain 2's and -2's.
  721.         foreach i $line {
  722.             if {$i == "2" || $i == "-2"} {incr lwhite $indent_amounts($i)} 
  723.         }
  724.        # Did the last line start with a lone \) or \} ?  If so, we want to
  725.         # keep the indent, and not make call it an unbalanced line.
  726.         if {[regexp {^[\t ]*(\}|\))} $pL1]} {
  727.             incr lwhite $indent_amounts(2)
  728.         } 
  729.     } 
  730.     # If we have a current line ...
  731.     if {[pos::compare [lindex $thisLine 0] == $posBeg]} {
  732.         # Reduce the indent if the first non-whitespace character of this
  733.         # line is ) or \}, or an "end" command.
  734.         set tL [lindex $thisLine 2]
  735.         if {$next == "\}" || $next == ")" || [regexp {^[\t ]*(\}|\)|end)} $tL]} {
  736.             incr lwhite $indent_amounts(-2)
  737.         } 
  738.     } 
  739.     # Now we return the level to the calling proc.
  740.     return [expr {$lwhite > 0 ? $lwhite : 0}]
  741. }
  742.  
  743. # ===========================================================================
  744. # Get Command Line
  745. # Find the next/prev command line relative to a given position, and return
  746. # the position in which it starts, its indentation, and the complete text
  747. # of the command line.  If the search for the next/prev command fails,
  748. # return an indentation level of 0.
  749. # Unlike SPSS and SAS modes, we don't have the luxury of ignoring commented
  750. # lines since they could simply indicate the continuation of commands.
  751.  
  752. proc Stta::getCommandLine {pos {direction 1} {ignoreComments 1}} {
  753.     
  754.     if {$ignoreComments == 1} {
  755.         set pat {^[\t ]*[^\t\r\n\*/ ]}
  756.     } elseif {$ignoreComments == 2} {
  757.         set pat {^[\t ]*[^\t\r\n/ ]}
  758.     } else {
  759.         set pat {^[\t ]*[^\t\r\n ]}
  760.     } 
  761.     set posBeg [pos::math [lineStart $pos] - 1]
  762.     if {[pos::compare $posBeg < [minPos]]} {
  763.         set posBeg [minPos]
  764.     } 
  765.     set lwhite 0
  766.     if {![catch {search -f $direction -r 1 $pat $pos} match]} {
  767.         set posBeg [lindex $match 0]
  768.         set lwhite [posX [pos::math [lindex $match 1] - 1]]
  769.     }
  770.     set posEnd [pos::math [nextLineStart $posBeg] - 1]
  771.     if {[pos::compare $posEnd > [maxPos]]} {
  772.         set posEnd [maxPos]
  773.     } 
  774.     return [list $posBeg $lwhite [getText $posBeg $posEnd]]
  775. }
  776.  
  777. # ===========================================================================
  778. # End of Command
  779. # Determine if the command in a line of a given position was terminated.
  780.  
  781. proc Stta::endOfCommand {line} {
  782.     
  783.     global SttamodeVars
  784.     
  785.     if {!$SttamodeVars(semiDelimiter)} {
  786.         # Check to see if the last line ended with /*, indicating continuation.
  787.         if {[regexp {/\*([^\*]*)$} $line]} {
  788.             return 0
  789.         } else {
  790.             return 1
  791.         }
  792.     } else {
  793.         # Check to see if the last line ended with ;, indicating termination.
  794.         if {[regexp {;([\t ]?)$} $line]} {
  795.             return 1
  796.         } else {
  797.             return 0
  798.         } 
  799.     }
  800. }
  801.  
  802. # ===========================================================================
  803. # ◊◊◊◊ Command Double Click ◊◊◊◊ #
  804. # First checks to see if this is a macro defined in current window.
  805. # Then checks to see if the highlighted word appears in any keyword list,
  806. # and if so, sends the selected word to the www.stata.com help site.  Stata
  807. # commands are case-sensitive, and so is the help search engine.
  808. #
  809. # Control-Command double click will insert syntax information in status bar.
  810. # Shift-Command double click will insert commented syntax information in window.
  811. # Option-Command double click will send the command to Stata application. (lps)
  812. # If "Local Help" is checked, option vs not is reversed, so that command
  813. # double-click will send to local Stata application.
  814.  
  815. proc Stta::DblClick {from to shift option control} {
  816.     
  817.     global SttamodeVars SttaCommands  SttaPrefixes   SttaParameters SttaFunctions 
  818.     global SttaModifiers SttaMacros   SttaDated      SttaSyntaxMessage
  819.     
  820.     set validCommands  [concat                                          \
  821.       $SttaCommands  $SttaPrefixes $SttaParameters $SttaFunctions       \
  822.       $SttaModifiers $SttaMacros   $SttaDated                           \
  823.       ]
  824.     
  825.     select $from $to
  826.     set command [getSelect]
  827.     set macroDef {program[\t ]define[\t ]*$command[\t\r\n; ]}
  828.     
  829.     if {![catch {search -f 1 -r 1 $macroDef [minPos]} match]} {
  830.         # First check current file for macro definition, and if found ...
  831.         placeBookmark
  832.         goto [lineStart [lindex $match 0]]
  833.         message "press <Ctl .> to return to original cursor position"
  834.         return
  835.         # Could next check any open windows, or files in the current
  836.         # window's folder ...  but not implemented.  For now, macros need
  837.         # to be defined in current file.
  838.     } elseif {[lsearch -exact $validCommands $command] == "-1"} {
  839.         # If not a defined macro, check to see if it's a defined keyword.
  840.         message "\"$command\" is not defined as a Stata system keyword."
  841.         return
  842.     }
  843.     # Any modifiers pressed?
  844.     if {$control} {
  845.         # CONTROL -- Just put syntax message in status bar window
  846.         if {[info exists SttaSyntaxMessage($command)]} {
  847.             message $SttaSyntaxMessage($command)        
  848.         } else {
  849.             message "Sorry, no syntax information available for $command"
  850.         } 
  851.     } elseif {$shift} {
  852.         # SHIFT --Just insert syntax message as commented text
  853.         if {[lsearch -exact $SttaDated $command] != "-1"} {
  854.             message "$SttaSyntaxMessage($command)"
  855.         } elseif {[info exists SttaSyntaxMessage($command)]} {
  856.             endOfLine
  857.             insertText "\r"
  858.             insertText "$SttaSyntaxMessage($command)"
  859.             comment::Line
  860.         } else {
  861.             message "Sorry, no syntax information available for $command"
  862.         } 
  863.     } elseif {$option && !$SttamodeVars(localHelp)} {
  864.         # Now we have four possibilities, based on "option" key and the
  865.         # preference for "local Help".
  866.         # 
  867.         # OPTION, local help isn't checked -- Send command to local application
  868.         Stta::localCommandHelp $command
  869.     } elseif {$option && $SttamodeVars(localHelp)} {
  870.         # OPTION, but local help is checked -- Send command for on-line help.
  871.         Stta::wwwCommandHelp $command
  872.     } elseif {$SttamodeVars(localHelp)} {
  873.         # No modifiers, local help is checked -- Send command to local app.
  874.         Stta::localCommandHelp $command
  875.     } else {
  876.         # No modifiers, no local help checked -- Send command for on-line
  877.         # help.  This is the "default" behavior.
  878.         Stta::wwwCommandHelp $command
  879.     }
  880. }
  881.  
  882. # ===========================================================================
  883. # WWW Command Help
  884. # Send command to defined url, prompting for text if necessary.
  885.  
  886. proc Stta::wwwCommandHelp {{command ""}} {
  887.     
  888.     global SttamodeVars
  889.     
  890.     if {$command == ""} {
  891.         set command [prompt "on-line help for ... " [getSelect]] 
  892.         # set command [statusPrompt "on-line help for ... " ] 
  893.     } 
  894.     message "\"$command\" sent to $SttamodeVars(helpUrl)"
  895.     url::execute $SttamodeVars(helpUrl)$command
  896. }
  897.  
  898. # ===========================================================================
  899. # Local Command Help
  900. # Send command to local application, prompting for text if necessary.
  901. # -- lps
  902. # Supposedly, this works on all platforms ... -- cbu
  903.  
  904. proc Stta::localCommandHelp {{command ""}} {
  905.     
  906.     if {$command == ""} {
  907.         set command [prompt "local Stata application help for ... " [getSelect]] 
  908.         # set command [statusPrompt "local Stata application help for ... " ] 
  909.     } 
  910.     Stta::doSelection "whelp $command"
  911. }
  912.  
  913. # ===========================================================================
  914. # Command Help
  915. # Send the command to a local Stata application if it exists, otherwise
  916. # send it the defined web site.  (Used in the "Statistical Modes Help"
  917. # file, could easily be used in the menu if desired ...)
  918.  
  919. proc Stta::commandHelp {{command ""}} {
  920.     
  921.     global SttamodeVars tcl_platform
  922.     
  923.     if {$command == ""} {
  924.         set command [prompt "Stata help for ..." ""]
  925.     } 
  926.     if {[set command [string trim $command]] == ""} {
  927.         message "Cancelled -- no command was entered."
  928.         error "No command was entered."
  929.     } 
  930.     if {[regexp $command " "]} {
  931.         message "Cancelled -- only enter one command for help."
  932.         error "Multiple commands requested."
  933.     } 
  934.     set pf $tcl_platform(platform)
  935.     set local 0
  936.     if {$pf == "macintosh" && ![catch {nameFromAppl $SttamodeVars(stataSig)}]} {
  937.         set local 1
  938.     } elseif {($pf == "windows" && [file exists $SttamodeVars(stataSig)]} {
  939.         set local 1
  940.     } elseif {($pf == "unix" && [file exists $SttamodeVars(stataSig)]} {
  941.         set local 1
  942.     } 
  943.     if {$local} {
  944.         Stta::localCommandHelp $command
  945.     } else {
  946.         Stta::wwwCommandHelp $command
  947.     } 
  948. }
  949.  
  950. # ===========================================================================
  951. # ◊◊◊◊ Mark File and Parse Functions ◊◊◊◊ #
  952. #
  953.  
  954. # ===========================================================================
  955. # Stta Mark File
  956. # This will return the first 35 characters from the first non-commented
  957. # word appearing in column 0.  Codebook files will be marked differently,
  958. # listing variable names.  All other output files (those not recognized)
  959. # will take into account the additional left margin elements added by
  960. # Stata.
  961. #
  962.  
  963. proc Stta::MarkFile {{type ""}} {
  964.     
  965.     removeAllMarks
  966.     
  967.     message "Marking File …"
  968.     
  969.     set pos [minPos]
  970.     set count 0
  971.     # Figure out what type of file this is -- source, codebook, or output.
  972.     # The variable "type" refers to a call from the Stata menu.
  973.     # Otherwise we try to figure out the type based on the file's suffix.
  974.     if {$type == ""} {
  975.         if {[win::CurrentTail] == "* Stta Mode Example *"} {
  976.             # Special case for Mode Examples, but only if called from
  977.             # Marks menu.  (Called from Stata menu, "type" will over-ride.
  978.             set type  ".do"
  979.         } else {
  980.             set type [file extension [win::CurrentTail]]
  981.         }
  982.     }
  983.     # Now set the mark regexp.
  984.     if {$type == ".do" || $type == ".ado"  } {
  985.         # Source file.
  986.         set markExpr {^(!+[\t ]|\*\*\*[ ]|\*\*\*\*[ ])?[a-zA-Z0-9_\#]}
  987.     } elseif {$type == ".codebook"} {
  988.         # Codebook file, called from the Stata menu
  989.         set markExpr {^[a-zA-Z0-9]+( \-)}
  990.     } else {
  991.         # None of the above, so assume that it's output
  992.         set markExpr {^(\. )+((!+[\t ]|\*\*\*[ ]|\*\*\*\*[ ])?[a-zA-Z0-9_\#])}
  993.     }
  994.     # Mark the file
  995.     while {![catch {search -f 1 -r 1 -m 0 -i 1 $markExpr $pos} match]} {
  996.         incr count
  997.         set posBeg [lindex $match 0]
  998.         set posEnd [nextLineStart $posBeg]
  999.         if {[pos::compare $posEnd > [maxPos]]} {set posEnd [maxPos]} 
  1000.         set line   [string trimright [getText $posBeg $posEnd]]
  1001.         # Get rid of the leading ". " for output files
  1002.         set line   [string trimleft  $line ". "]
  1003.         # Get rid of braces.
  1004.         regsub -all {\{|\[} $line {(} line
  1005.         regsub -all {\}|\]} $line {)} line
  1006.         # Add a little indentation so that section marks show up better.
  1007.         set line  "  $line"
  1008.         if {[regsub {  \*\*\*\* } $line {* } line]} {
  1009.             incr count -1
  1010.         } elseif {[regsub {  \*\*\* } $line {• } line]} {
  1011.             incr count -1
  1012.         } 
  1013.         if {[string length $line] > 35} {
  1014.             set line "[string range $line 0 35] …"
  1015.         } else {
  1016.             # Get rid of trailing sem-colons.
  1017.             set line  [string trimright $line ";" ]
  1018.         }
  1019.         if {$type == ".codebook"} {
  1020.             # Get rid of the trailing "-" for frequency / codebook files.
  1021.             regsub {[-]+( …)} $line { } line
  1022.             set line [string trimleft  $line " "]
  1023.             message "# of variables: $count"
  1024.         }
  1025.         setNamedMark $line $posBeg $posBeg $posBeg
  1026.         set pos $posEnd
  1027.     }
  1028.     # Sorting the marks if this is a codebook.
  1029.     # (Code lifted from "sortMarksFile", in "marks.tcl")
  1030.     if {$type == ".codebook"} {
  1031.         message "Sorting marks …"
  1032.         set mks {}
  1033.         foreach mk [getNamedMarks] {
  1034.             removeNamedMark -n [lindex $mk 0] -w [lindex $mk 1]
  1035.             lappend mks $mk
  1036.         }
  1037.         foreach mk   [lsort $mks] {
  1038.             set name [lindex $mk 0]
  1039.             set disp [lindex $mk 2]
  1040.             set pos  [lindex $mk 3]
  1041.             set end  [lindex $mk 4]
  1042.             
  1043.             setNamedMark $name $disp $pos $end
  1044.         }
  1045.         message "This codebook describes $count variables."
  1046.     } else {
  1047.         message "This file contains $count commands."
  1048.     } 
  1049. }
  1050.  
  1051. # ===========================================================================
  1052. # Stta Parse Functions
  1053. # This will return only the Stta command names.  All other output files
  1054. # (those not recognized) will take into account the additional left margin
  1055. # elements added by Stata.
  1056.  
  1057. proc Stta::parseFuncs {} {
  1058.     
  1059.     global sortFuncsMenu
  1060.     
  1061.     set ext [file extension [win::CurrentTail]]
  1062.     
  1063.     # Determine the file type.
  1064.     if {$ext == ".do" || $ext == ".ado"} {
  1065.         set funcExpr {^(\w+)}
  1066.     } elseif {[file tail [win::Current]] == "* Stta Mode Example *"} {
  1067.         # Special case for Mode Examples folder
  1068.         set funcExpr {^(\w+)}
  1069.     } else {
  1070.         # We don't worry about codebooks here, we'll just parse as output.
  1071.         set funcExpr {^(\. )(\w+)}
  1072.     }
  1073.     # Parse the file.
  1074.     set pos [minPos]
  1075.     set m {}
  1076.     while {[set match [search -f 1 -r 1 -i 0 -n $funcExpr $pos]] != ""} {
  1077.         if {[regexp -- {(\w+)} [eval getText $match] "" word]} {
  1078.             lappend m [list $word [lindex $match 0]]
  1079.         }
  1080.         set pos [lindex $match 1]
  1081.     }
  1082.     # Sort the functions if necessary, but regsub either way.
  1083.     if {$sortFuncsMenu} {
  1084.         regsub -all "\[\{\}\]" [lsort -ignore $m] "" m
  1085.     } else {
  1086.         regsub -all "\[\{\}\]" $m "" m
  1087.     }   
  1088.     return  $m
  1089. }
  1090.  
  1091. # ===========================================================================
  1092. # ◊◊◊◊ -------------------- ◊◊◊◊ #
  1093. # ◊◊◊◊ Stata Menu ◊◊◊◊ #
  1094. # version: 1.2
  1095. # Author: L. Phillip Schumm
  1096. # E-mail: <pschumm@uchicago.edu>
  1097. # If Stata is launched from Alpha, then Stata's own directory will become
  1098. # the working directory unless a profile.do file is used to change it.
  1099. #
  1100. # version history:
  1101. # 1.1  lps  Contributed menu to stataMode.tcl
  1102. # 1.2  cbu  Added "Mark File As", simplified Stta::menuProc .
  1103. #           Added "Help", added optional argument to doFile .
  1104. #           Changed "Menu -n ..." proc to "menu::buildProc stataMenu ...".
  1105. # 1.3  cbu  Added more preferences to Help section, and Navigation section.
  1106. # 2.0  cbu  Updated for Alpha 7.4, added "Stata Home Page" menu item.
  1107. # 2.1  cbu  Added "Keywords" submenu, cleaning up "Help"
  1108.  
  1109. # This was the old menu definition proc.
  1110.  
  1111. # Menu -n $stataMenu -p Stta::menuProc -M Stta {
  1112. #     "/S<U<OswitchToStata"
  1113. #     "(-"
  1114. #     "/D<U<OdoFile"
  1115. #     "/D<U<O<BdoSelection"
  1116. #     {Menu -n markStataFileAs -p Stta::markFileProc {
  1117. #         "source"
  1118. #         "output"
  1119. #         "codebook"  }
  1120. #     }
  1121. #     {Menu -n StataHelp -p Stta::helpProc {
  1122. #         "/t<BstataModeHelp"
  1123. #         "/t<IlocalCommandHelp…"
  1124. #         "/t<OwwwCommandHelp…" }
  1125. #     }
  1126. #     "(-"
  1127. #     "/P<U<OinsertPath"
  1128. #     "/P<U<O<BprogramTemplate"
  1129. # }
  1130.  
  1131. # Tell Alpha what procedures to use to build all menus, submenus.
  1132.  
  1133. menu::buildProc stataMenu           Stta::buildMenu
  1134. menu::buildProc stataHelp           Stta::buildHelpMenu
  1135. menu::buildProc stataKeywords       Stta::buildKeywordsMenu
  1136. menu::buildProc markStataFileAs…    Stta::buildMarkMenu
  1137.  
  1138. # First build the main Stata menu.
  1139.  
  1140. proc Stta::buildMenu {} {
  1141.     
  1142.     global stataMenu
  1143.     
  1144.     set menuList [list                                  \
  1145.       "stataHomePage"                                   \
  1146.       "/S<U<OswitchToStata"                             \
  1147.       [list Menu -n stataHelp           -M Stta {}]     \
  1148.       "(-"                                              \
  1149.       [list Menu -n stataKeywords       -M Stta {}]     \
  1150.       [list Menu -n markStataFileAs…    -M Stta {}]     \
  1151.       "(-"                                              \
  1152.       "/D<U<OdoFile"                                    \
  1153.       "/D<U<O<BdoSelection"                             \
  1154.       "(-"                                              \
  1155.       "/P<U<OinsertPath"                                \
  1156.       "/P<U<O<BprogramTemplate"                         \
  1157.       "/b<UcontinueCommand"                             \
  1158.       "(-"                                              \
  1159.       "/N<U<BnextCommand"                               \
  1160.       "/P<U<BprevCommand"                               \
  1161.       "/S<U<BselectCommand"                             \
  1162.       "/I<B<OreformatCommand"                           \
  1163.       ]
  1164.     set submenus [list stataHelp stataKeywords markStataFileAs… ]
  1165.     return       [list build $menuList Stta::menuProc $submenus $stataMenu]
  1166. }
  1167.  
  1168. # Then build the "Stata Help" submenu.
  1169.  
  1170. proc Stta::buildHelpMenu {} {
  1171.     
  1172.     global SttamodeVars SttaPrefsInMenu alpha::platform
  1173.     
  1174.     # Determine which key should be used for "Help", with F8 as option.
  1175.     
  1176.     if {!$SttamodeVars(noHelpKey)} {
  1177.         set key "/t"
  1178.     } else {
  1179.         set key "/l"
  1180.     } 
  1181.     
  1182.     # Reverse the local, www key bindings depending on the value of the
  1183.     # 'Local Help" variable.
  1184.     
  1185.     if {!$SttamodeVars(localHelp)} {
  1186.         set menuList [list                  \
  1187.           "${key}<OwwwCommandHelp…"         \
  1188.           "${key}<IlocalCommandHelp…"       \
  1189.           ]
  1190.     } else {
  1191.         set menuList [list                  \
  1192.           "${key}<OlocalCommandHelp…"       \
  1193.           "${key}<IwwwCommandHelp…"         \
  1194.           ]
  1195.     } 
  1196.     lappend menuList "(-"
  1197.     if {${alpha::platform} == "alpha"} {
  1198.         set prefix "!√"
  1199.     } else {
  1200.         set prefix "!•"
  1201.     } 
  1202.     foreach pref $SttaPrefsInMenu {
  1203.         if {$SttamodeVars($pref)} {
  1204.             if {$pref == "semiDelimiter"} {set pref "/;<U<B$pref"}
  1205.             lappend menuList "${prefix}$pref"
  1206.         } else {
  1207.             if {$pref == "semiDelimiter"} {set pref "/;<U<B$pref"}
  1208.             lappend menuList "$pref"
  1209.         }
  1210.     }
  1211.     lappend menuList "(-"
  1212.     lappend menuList "setStataApplication"
  1213.     lappend menuList "(-"
  1214.     lappend menuList "${key}<BstataModeHelp"
  1215.     
  1216.     return [list build $menuList Stta::helpProc {}]
  1217. }
  1218.  
  1219. # Then build the "Stta Mode Keywords" submenu.
  1220.  
  1221. proc Stta::buildKeywordsMenu {} {
  1222.     
  1223.     set menuList [list                  \
  1224.       "listKeywords"                    \
  1225.       "checkKeywords"                   \
  1226.       "addNewCommands"                  \
  1227.       "addNewOptions"                   \
  1228.       ]
  1229.     return [list build $menuList Stta::keywordsProc {}]
  1230. }
  1231.  
  1232. # Then build the "Mark Stata File As" submenu.
  1233.  
  1234. proc Stta::buildMarkMenu {} {
  1235.     
  1236.     global SttamodeVars alpha::platform
  1237.     
  1238.     set menuList [list                  \
  1239.       "source"                          \
  1240.       "output"                          \
  1241.       "codebook"                        \
  1242.       "(-"                              \
  1243.       ]
  1244.     if {${alpha::platform} == "alpha"} {
  1245.         set prefix "!√"
  1246.     } else {
  1247.         set prefix "!•"
  1248.     } 
  1249.     if {$SttamodeVars(autoMark)} {
  1250.         lappend menuList "${prefix}autoMark"
  1251.     } else {
  1252.         lappend menuList "autoMark"        
  1253.     }
  1254.  
  1255.     return [list build $menuList Stta::markFileProc {}]
  1256. }
  1257.  
  1258.  
  1259. proc Stta::rebuildMenu {{menuName "stataMenu"} {pref ""}} {
  1260.     menu::buildSome $menuName
  1261. }
  1262.  
  1263. # Dim some menu items when there are no open windows.
  1264. set menuItems {
  1265.     markStataFileAs… doFile doSelection 
  1266.     insertPath programTamplate continueCommand
  1267.     nextCommand prevCommand selectCommand reformatCommand
  1268. }
  1269. foreach i $menuItems {
  1270.     hook::register requireOpenWindowsHook [list stataMenu $i] 1
  1271. unset i menuItems 
  1272.  
  1273. # Now we actually build the Stata menu.
  1274.  
  1275. menu::buildSome stataMenu
  1276.  
  1277. # ===========================================================================
  1278. # ◊◊◊◊ Stata menu support ◊◊◊◊ #
  1279.  
  1280. # This is the procedure called for all main menu items.
  1281.  
  1282. proc Stta::menuProc {menuName item} {Stta::$item}
  1283.  
  1284. # Give a beta message for untested features / menu items.
  1285.  
  1286. proc Stta::betaMessage {{kill 1}} {
  1287.     
  1288.     message "Sorry,this feature has not been fully implemented."
  1289.     if {$kill} {return -code return}
  1290. }
  1291.  
  1292. # ===========================================================================
  1293. # Open the Stata home page.
  1294.  
  1295. proc Stta::stataHomePage {} {
  1296.  
  1297.     global SttamodeVars
  1298.     
  1299.     url::execute $SttamodeVars(stataHomePage)
  1300. }
  1301.  
  1302. # ===========================================================================
  1303. # Switch to Stata application.
  1304.  
  1305. proc Stta::switchToStata {} {app::launchFore [Stta::sig]}
  1306.  
  1307. # ===========================================================================
  1308. # Return the Stata signature.
  1309.  
  1310. proc Stta::sig {{app "Stata"}} {
  1311.     
  1312.     global SttamodeVars tcl_platform
  1313.     
  1314.     set lowApp [string tolower $app]
  1315.     set capApp [string toupper $app]
  1316.     set pf     $tcl_platform(platform)
  1317.  
  1318.     if {$pf == "macintosh"} {
  1319.         # Make sure that the Macintosh application for the signature exists.
  1320.         if {[catch {nameFromAppl $SttamodeVars(${lowApp}Sig)}]} {
  1321.             alertnote "Looking for the $capApp application ..."
  1322.             Stta::setApplication $lowApp
  1323.         }
  1324.     } elseif {$pf == "windows" || $pf == "unix"} {
  1325.         # Make sure that the Windows application for the signature exists. 
  1326.         # We assume that this will work for unix, too.
  1327.         if {![file exists $SttamodeVars(${lowApp}Sig)]} {
  1328.             alertnote "Looking for the $capApp application ..."
  1329.             Stta::setApplication $lowApp
  1330.         }
  1331.     }
  1332.     return $SttamodeVars(${lowApp}Sig)
  1333. }
  1334.  
  1335. # ===========================================================================
  1336. # Set Application
  1337. # Prompt the user to locate the local Stata application.
  1338.  
  1339. proc Stta::setApplication {{app "Stata"}} {
  1340.     
  1341.     global mode SttamodeVars
  1342.     
  1343.     set lowApp [string tolower $app]
  1344.     set capApp [string toupper $app]
  1345.     
  1346.     set newSig ""
  1347.     set newSig [dialog::askFindApp $capApp $SttamodeVars(${lowApp}Sig)]
  1348.     
  1349.     if {$newSig != ""} {
  1350.         set SttamodeVars(${lowApp}Sig) "$newSig"
  1351.         set oldMode $mode
  1352.         set mode "Stta"
  1353.         synchroniseModeVar "${lowApp}Sig" $SttamodeVars(${lowApp}Sig)
  1354.         set mode $oldMode
  1355.         message "The $capApp signature has been changed to \"$newSig\"."
  1356.     } else {
  1357.         message "Cancelled."
  1358.     }
  1359. }
  1360.  
  1361. # ===========================================================================
  1362. # ◊◊◊◊ Help ◊◊◊◊ #
  1363.  
  1364. proc Stta::helpProc {menuName item} {
  1365.  
  1366.     global SttamodeVars SttaPrefsInMenu
  1367.     
  1368.     if {$item == "wwwCommandHelp"} {
  1369.         Stta::wwwCommandHelp
  1370.     } elseif  {$item == "localCommandHelp"} {
  1371.         Stta::localCommandHelp
  1372.     } elseif {[lsearch -exact $SttaPrefsInMenu $item] != -1} {
  1373.         Stta::flagFlip $item
  1374.         Stta::rebuildMenu stataHelp
  1375.     } elseif {$item == "setStataApplication"} {
  1376.         Stta::setApplication "Stata"
  1377.     } elseif {$item == "stataModeHelp"} {
  1378.         package::helpFile "Stta"
  1379.     } else {
  1380.         Stta::$item
  1381.     } 
  1382. }
  1383.  
  1384. # ===========================================================================
  1385. # ◊◊◊◊ Keywords ◊◊◊◊ #
  1386.  
  1387. proc Stta::keywordsProc {menuName item} {
  1388.  
  1389.     global Sttacmds
  1390.     
  1391.     if {$item == "listKeywords"} {
  1392.         set keywords [listpick -l -p "Current Stata mode keywords…" $Sttacmds]
  1393.         foreach keyword $keywords {
  1394.             Stta::checkKeywords $keyword
  1395.         }
  1396.     } elseif {$item == "addNewCommands" || $item == "addNewOptions"} {
  1397.         set item [string trimleft $item "addNew"]
  1398.         if {$item == "Commands" && [llength [winNames]] && [askyesno \
  1399.           "Would you like to add all of the \"extra\" commands from this window\
  1400.           to the \"Add Commands\" preference?"] == "yes"} {
  1401.             Stta::addWindowCommands
  1402.         } else {
  1403.             Stta::addKeywords $item
  1404.         }
  1405.     } else {
  1406.         Stta::$item
  1407.     } 
  1408. }
  1409.  
  1410. # ===========================================================================
  1411. # Stta::addWindowCommands
  1412. # Add all of the "extra" commands which appear in entries in this window.
  1413.  
  1414. proc Stta::addWindowCommands {} {
  1415.     
  1416.     global mode Sttacmds SttamodeVars
  1417.     
  1418.     if {![llength [winNames]]} {
  1419.         message "Cancelled -- no current window!"
  1420.         return
  1421.     } 
  1422.     
  1423.     message "Scanning [win::CurrentTail] for all commands…"
  1424.     
  1425.     set pos [minPos]
  1426.     set pat {^([a-zA-Z0-9]+[a-zA-Z0-9])+[\t ]}
  1427.     while {![catch {search -f 1 -r 1 $pat $pos} match]} {
  1428.         set pos [nextLineStart [lindex $match 1]]
  1429.         set commandLine [getText [lindex $match 0] [lindex $match 1]]
  1430.         regexp $pat $commandLine match aCommand
  1431.         if {![lcontains Sttacmds $aCommand]} {
  1432.             append SttamodeVars(addCommands) " $aCommand"
  1433.         } 
  1434.     }
  1435.     set SttamodeVars(addCommands) [lsort [lunique $SttamodeVars(addCommands)]]
  1436.     set oldMode $mode
  1437.     set mode "Stta"
  1438.     synchroniseModeVar addCommands $SttamodeVars(addCommands)
  1439.     set mode $oldMode
  1440.     if {[llength $SttamodeVars(addCommands)]} {
  1441.         Stta::colorizeStta
  1442.         listpick -p "The \"Add Commands\" preference includes:" \
  1443.           $SttamodeVars(addCommands)
  1444.         message "Use the \"Mode Prefs --> Preferences\" menu item to edit keyword lists."
  1445.     } else {
  1446.         message "No \"extra\" commands from this window were found."
  1447.     } 
  1448. }
  1449.  
  1450. # ===========================================================================
  1451. # Stta::addKeywords
  1452. # Prompt the user to add keywords for a given category.
  1453.  
  1454. proc Stta::addKeywords {{category} {keywords ""}} {
  1455.  
  1456.     global mode SttamodeVars
  1457.     
  1458.     if {$keywords == ""} {
  1459.         set keywords [prompt "Enter new Stata $category:" ""]
  1460.     }
  1461.     
  1462.     # Check to see if the keyword is already defined.
  1463.     foreach keyword $keywords {
  1464.         set checkStatus [Stta::checkKeywords $keyword 1 0]
  1465.         if {$checkStatus != 0} {
  1466.             alertnote "Sorry, \"$keyword\" is already defined\
  1467.               in the $checkStatus list."
  1468.             message "Cancelled."
  1469.             return -code return
  1470.         } 
  1471.     }
  1472.     # Keywords are all new, so add them to the appropriate mode preference.
  1473.     append SttamodeVars(add$category) " $keywords"
  1474.     set SttamodeVars(add$category) [lsort $SttamodeVars(add$category)]
  1475.     set oldMode $mode
  1476.     set mode "Stta"
  1477.     synchroniseModeVar add$category $SttamodeVars(add$category)
  1478.     set mode $oldMode
  1479.     Stta::colorizeStta
  1480.     message "\"$keywords\" added to $category preference."
  1481. }
  1482.  
  1483. proc Stta::checkKeywords {{newKeywordList ""} {quietly 0} {noPrefs 0}} {
  1484.     
  1485.     global SttamodeVars
  1486.     
  1487.     global SttaCommands  SttaUserCommands  SttaPrefixes    SttaParameters
  1488.     global SttaFunctions SttaOptions       SttaUserOptions SttaModifiers
  1489.     global SttaMacros    SttaDated
  1490.     
  1491.     set type 0
  1492.     if {$newKeywordList == ""} {
  1493.         set quietly 0
  1494.         set newKeywordList [prompt "Enter Stata mode keywords to be checked:" ""]
  1495.     }
  1496.     # Check to see if the new keyword(s) is already defined.
  1497.     foreach newKeyword $newKeywordList {
  1498.         if {[lsearch -exact $SttaCommands $newKeyword] != "-1"} {
  1499.             set type SttaCommands
  1500.         } elseif {[lsearch -exact $SttaUserCommands $newKeyword] != "-1"} {
  1501.             set type SttaUserCommands
  1502.         } elseif {[lsearch -exact $SttaPrefixes $newKeyword] != "-1"} {
  1503.             set type SttaPrefixes
  1504.         } elseif {[lsearch -exact $SttaParameters $newKeyword] != "-1"} {
  1505.             set type SttaParameters
  1506.         } elseif {[lsearch -exact $SttaFunctions $newKeyword] != "-1"} {
  1507.             set type SttaFunctions
  1508.         } elseif {[lsearch -exact $SttaOptions $newKeyword] != "-1"} {
  1509.             set type SttaOptions
  1510.         } elseif {[lsearch -exact $SttaUserOptions $newKeyword] != "-1"} {
  1511.             set type SttaUserOptions
  1512.         } elseif {[lsearch -exact $SttaModifiers $newKeyword] != "-1"} {
  1513.             set type SttaModifiers
  1514.         } elseif {[lsearch -exact $SttaMacros $newKeyword] != "-1"} {
  1515.             set type SttaMacros
  1516.         } elseif {[lsearch -exact $SttaDated $newKeyword] != "-1"} {
  1517.             set type SttaDated
  1518.         } elseif {!$noPrefs && \
  1519.           [lsearch -exact $SttamodeVars(addCommands) $newKeyword] != "-1"} {
  1520.             set type SttamodeVars(addCommands)
  1521.         } elseif {!$noPrefs && \
  1522.           [lsearch -exact $SttamodeVars(addOptions) $newKeyword] != "-1"} {
  1523.             set type SttamodeVars(addOptions)
  1524.         }
  1525.         if {$quietly} {
  1526.             # When this is called from other code, it should only contain
  1527.             # one keyword to be checked, and we'll return it's type.
  1528.             return "$type"
  1529.         } elseif {!$quietly && $type == 0} {
  1530.             alertnote "\"$newKeyword\" is not currently defined\
  1531.               as a Stta mode keyword."
  1532.         } elseif {$type != 0} {
  1533.             # This will work for any other value for "quietly", such as 2
  1534.             alertnote "\"$newKeyword\" is currently defined as a keyword\
  1535.               in the \"$type\" list."
  1536.         } 
  1537.         set type 0
  1538.     }
  1539. }
  1540.  
  1541. # ===========================================================================
  1542. # ◊◊◊◊ Marks ◊◊◊◊ #
  1543.  
  1544. proc Stta::markFileProc {menuName item} {
  1545.     
  1546.     if {$item == "source"} {
  1547.         Stta::MarkFile {.do}
  1548.     } elseif {$item == "output"} {
  1549.         # doesn't really matter what we put for the mark file "type" here,
  1550.         # since output is the default if other "if ..." cases aren't met.
  1551.         Stta::MarkFile {.out}
  1552.     } elseif {$item == "codebook"} {
  1553.         Stta::MarkFile {.codebook}
  1554.     } elseif {$item == "autoMark"} {
  1555.         Stta::flagFlip autoMark
  1556.         Stta::rebuildMenu markStataFileAs…
  1557.     }
  1558. }
  1559.  
  1560. # ===========================================================================
  1561. # ◊◊◊◊ Processing ◊◊◊◊ #
  1562.  
  1563. # ===========================================================================
  1564. # Do FIle
  1565. # Send entire file to Stata for processing, adding carriage return at end
  1566. # of file if necessary.  Note that unlike Stata's do-file editor, the name
  1567. # of the actual file appears in Stata's output window!
  1568. # Optional "f" argument allows this to be called by other code, or to be 
  1569. # sent via a Tcl shell window.
  1570.  
  1571. proc Stta::doFile {{f ""} {app "Stata"}} {
  1572.     
  1573.     if {$f != ""} {file::openAny $f}
  1574.     set f [win::Current]
  1575.  
  1576.     set dirtyWindow [winDirty]
  1577.     set dontSave 0
  1578.     if {$dirtyWindow && [askyesno \
  1579.       "Do you want to save the file before sending it to Stata?"] == "yes"} {
  1580.         save
  1581.     } else {
  1582.         set dontSave 1
  1583.     } 
  1584.     if {!$dontSave && [lookAt [pos::math [maxPos] - 1]] != "\r"} {
  1585.         set pos [getPos]
  1586.         goto [maxPos]
  1587.         insertText "\r"
  1588.         goto $pos
  1589.         alertnote "Carriage return added to end of file."
  1590.         save
  1591.     }
  1592.  
  1593.     app::launchBack '[Stta::sig]'
  1594.     sendOpenEvent noReply '[Stta::sig]' $f
  1595.     switchTo '[Stta::sig]'
  1596. }
  1597.  
  1598. # ===========================================================================
  1599. # Do Selection
  1600. # Procedure to implement transfer of selected lines to Stata for processing.
  1601.  
  1602. proc Stta::doSelection {{selection ""} {app "Stata"}} {
  1603.     
  1604.     global PREFS
  1605.     
  1606.     if {$selection == ""} {
  1607.         if {![isSelection]} {
  1608.             message "No selection -- cancelled."
  1609.             return
  1610.         } else {
  1611.             set selection [getSelect]
  1612.         } 
  1613.     }
  1614.     file::ensureDirExists [file join $PREFS Stata-tmp]
  1615.     set newFile [file join $PREFS Stata-tmp temp-Stata.do]
  1616.     file::writeAll $newFile $selection 1
  1617.  
  1618.     app::launchBack '[Stta::sig]'
  1619.     sendOpenEvent noReply '[Stta::sig]' $newFile
  1620.     switchTo '[Stta::sig]'
  1621. }
  1622.  
  1623. proc Stta::quitHook {} {temp::cleanup Stata-tmp}
  1624.  
  1625. # ===========================================================================
  1626. # ◊◊◊◊ Insertions ◊◊◊◊ #
  1627.  
  1628. proc Stta::insertPath {} {
  1629.     
  1630.     global file::separator
  1631.     
  1632.     set path ""
  1633.     set t    ""
  1634.     append t "\"${file::separator}"
  1635.     set path [getfile "Choose path of target file:"]
  1636.     if {$path != ""} {
  1637.         append t $path
  1638.         append t "\""
  1639.         typeText $t
  1640.     }
  1641. }
  1642.  
  1643. # An example of Stata specific electric insertion templates that could be
  1644. # added to the menu.
  1645.  
  1646. proc Stta::programTemplate {} {
  1647.  
  1648.     global SttamodeVars
  1649.     
  1650.     set end [lindex [Stta::getCommand [getPos]] 1]
  1651.     if {$end != "-1" && $end > [getPos]} {
  1652.         goto $end
  1653.     }
  1654.     if {$SttamodeVars(semiDelimiter)} {
  1655.         set eol " ;\r"
  1656.     } else {
  1657.         set eol "\r"
  1658.     } 
  1659.     
  1660.     set    pt "program define •progname•${eol}\tversion 6.0${eol}\tif \"`1'\""
  1661.     append pt " == \"?\" {\r\t\tglobal S_1 \"•variable names•\"${eol}\t\t"
  1662.     append pt "exit${eol}\t}${eol}\t••\r\t* (each result below must correspond"
  1663.     append pt " to a variable in S_1)${eol}\tpost `1' •results•${eol}end${eol}"
  1664.     elec::Insertion $pt
  1665. }
  1666.  
  1667. # ===========================================================================
  1668. # ◊◊◊◊ Navigation ◊◊◊◊ #
  1669.  
  1670. # Next/Prev command can simply return the position of the next command
  1671. # (quietly == 1), move the cursor to the next command (placing the cursor
  1672. # at the top of the window if toTop == 1), extend the current selection to
  1673. # the end of the this command, or (if the current command is already
  1674. # highlighted in its entirety) extend the current selection to the end of
  1675. # the next command.
  1676.  
  1677. proc Stta::nextCommand {{quietly 0} {toTop 0}} {
  1678.     
  1679.     if {[pos::compare [selEnd] == [maxPos]]} {
  1680.         set pos [maxPos]
  1681.     } else {
  1682.         set pos [pos::math [selEnd] + 1]
  1683.     } 
  1684.     set pat {^[^\r\n\t \*/]}
  1685.  
  1686.     if {![catch {search -f 1 -r 1 $pat $pos} match]} {
  1687.         set pos [lineStart [lindex $match 1]]
  1688.     } else {
  1689.         set pos [maxPos]
  1690.     }
  1691.     if {$quietly} {
  1692.         return $pos
  1693.     } elseif {[isSelection]} {
  1694.     set limit1 [lindex [Stta::getCommand [selEnd]] 1]
  1695.     set limit2 [lindex [Stta::getCommand $pos    ] 1]
  1696.     if {$limit2 == "-1"} {set limit2 [maxPos]}
  1697.     if {$limit1 == "-1"} {set limit1 $limit2}
  1698.     if {[pos::compare [selEnd] < $limit1]} {
  1699.         select [getPos] $limit1
  1700.     } else {
  1701.         select [getPos] $limit2
  1702.     } 
  1703.     } elseif {$pos == [maxPos]} {
  1704.     message "No further commands in the file."
  1705.     return
  1706.     } else {
  1707.     goto $pos
  1708.     message [getText $pos [nextLineStart $pos]]
  1709.     } 
  1710.     if {$toTop} {insertToTop}
  1711. }
  1712.  
  1713. proc Stta::prevCommand {{quietly 0} {toTop 0}} {
  1714.     
  1715.     if {[pos::compare [getPos] == [minPos]]} {
  1716.         set pos [minPos]
  1717.     } else {
  1718.         set pos [pos::math [getPos] - 1]
  1719.     } 
  1720.     set pat {^[^\r\n\t \*/]}
  1721.  
  1722.     if {![catch {search -f 0 -r 1 $pat $pos} match]} {
  1723.         set pos [lineStart [lindex $match 1]]
  1724.     } else {
  1725.         set pos [minPos]
  1726.     }
  1727.     if {$quietly} {
  1728.     return $pos
  1729.     } elseif {[isSelection]} {
  1730.     # Going backwards is actually easier with selections.
  1731.     select $pos [selEnd]
  1732.     } elseif {$pos == [minPos]} {
  1733.     message "No further commands in the file."
  1734.     return
  1735.     } else {
  1736.     goto $pos
  1737.     message [getText $pos [nextLineStart $pos]]
  1738.     } 
  1739.     if {$toTop} {insertToTop}
  1740.     return $pos
  1741. }
  1742.  
  1743. proc Stta::searchFunc {direction} {
  1744.     
  1745.     if {$direction} {
  1746.         Stta::nextCommand
  1747.     } else {
  1748.         Stta::prevCommand
  1749.     }
  1750. }
  1751.  
  1752. proc Stta::selectCommand {} {
  1753.     
  1754.     set pos    [getPos]
  1755.     set limits [Stta::getCommand $pos]
  1756.     set posBeg [lindex $limits 0]
  1757.     set posEnd [lindex $limits 1]
  1758.     set test1  [pos::compare $pos >= $posBeg]
  1759.     set test2  [pos::compare $pos <= $posEnd]
  1760.     if {$posBeg != "-1" && $test1 && $test2} {
  1761.         select $posBeg $posEnd
  1762.     } else {
  1763.         message "The cursor is not within a command."
  1764.         error "The cursor is not within a command."
  1765.     } 
  1766. }
  1767.  
  1768. proc Stta::copyCommand {{quietly 0}} {
  1769.     
  1770.     set pos [getPos]
  1771.     if {[set posBeg [lindex [Stta::getCommand $pos] 0]] != "-1"} {
  1772.         goto $posBeg
  1773.         forwardWord
  1774.         set posEnd [getPos]
  1775.         if {!$quietly} {
  1776.             select $posBeg $posEnd
  1777.             copy
  1778.             message "\"[getText $posBeg $posEnd]\" copied to clipboard."
  1779.         } 
  1780.         goto $pos
  1781.         return [getText $posBeg $posEnd]
  1782.     } elseif {!$quietly} {
  1783.         message "The cursor is not within a command."
  1784.     }
  1785.     return ""
  1786. }
  1787.  
  1788. proc Stta::reformatCommand {} {
  1789.     
  1790.     if {![isSelection]} {Stta::selectCommand} 
  1791.     message "Reformatting …"
  1792.     ::indentRegion
  1793.     goto [pos::math [getPos] -1]
  1794.     goto [Stta::nextCommand 1]
  1795.     message "Reformatted."
  1796. }
  1797.  
  1798. proc Stta::getCommand {pos} {
  1799.     
  1800.     set pos1 [pos::math [nextLineStart $pos] - 1]
  1801.     set pat {^[^\r\n\t \}\)]}
  1802.     set posBeg "-1"
  1803.     set posEnd "-1"
  1804.     if {![catch {search -f 0 -r 1 $pat $pos1} match]} {
  1805.         set posBeg [lindex $match 0]
  1806.         set pos2   [nextLineStart $posBeg]
  1807.         if {![catch {search -f 1 -r 1 $pat $pos2} match]} {
  1808.             set posEnd [lindex $match 0]
  1809.         } else {
  1810.             set posEnd [maxPos]
  1811.         } 
  1812.         # Now back up to remove empty or commented lines.
  1813.         set posEndPrev [pos::math $posEnd - 1]
  1814.         set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1815.         while {[regexp {^[\t ]*$} $prevLine]} {
  1816.             set posEnd [lineStart $posEndPrev]
  1817.             set posEndPrev [pos::math $posEnd - 1]
  1818.             set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1819.         }
  1820.     } 
  1821.     return [list $posBeg $posEnd]
  1822. }
  1823.  
  1824. # ===========================================================================
  1825. # ◊◊◊◊ --------------------- ◊◊◊◊ #
  1826. # ◊◊◊◊ version history ◊◊◊◊ #
  1827. #  modified by  vers#  reason
  1828. #  -------- --- ------ -----------
  1829. #  01/28/20 cbu 1.0.1  First created Stata mode, based upon other modes found 
  1830. #                        in Alpha's distribution.  Commands are based on 
  1831. #                        release version 3.1 of Stata.
  1832. #  03/02/20 cbu 1.0.2  Minor modifications to comment handling.
  1833. #  03/20/00 cbu 1.0.3  Minor update of keywords dictionaries. 
  1834. #                      Renamed mode Stta, from stta 
  1835. #  04/01/00 cbu 1.0.4  Added new preferences to allow the user to enter 
  1836. #                        additional commands and options.  
  1837. #                      Reduced the number of different user-specified colors.
  1838. #                      Added "Stta::updateColors" to avoid need for a restart.
  1839. #  04/08/00 cbu 1.0.5  Unset obsolete preferences from earlier versions.
  1840. #                      Modified "Stta::electricSemi", added key-bindings for
  1841. #                        "Continue Comment", and "Electric Return Over-ride".
  1842. #                      Renamed "Stta::updateColors" to "Stta::updatePreferences".
  1843. #  04/16/00 cbu 1.1    Renamed to stataMode.tcl
  1844. #                      Added "Stta::MarkFile" and "Stta::parseFuncs".
  1845. #                      Added command double-click for on-line help.
  1846. #  06/20/00 cbu 1.2    "Mark File" now recognizes headings as well as commands.
  1847. #                      "Mark File" recognizes source, output, or codebook files.
  1848. #                      Completions, Completions Tutorial added.
  1849. #                      "Reload Completions", referenced by "Update Preferences".
  1850. #                      Better support for user defined keywords.
  1851. #                      Removed "Continue Comment", now global in Alpha 7.4.
  1852. #                      <shift, control>-<command> double-click syntax info.
  1853. #           lps        <option>-<command> double-click Stata app .hlp help.
  1854. #           lps        Added Phil Schumm's Stata Menu.
  1855. #           lps        Added "Continue Command" key binding and proc.
  1856. #                      Added "localHelpOnly" variable for command double-click.
  1857. #  08/23/00 cbu 1.2.1  "Mark File As" added to Stata menu.  (Required adding
  1858. #                        an optional argument to Stta::MarkFile, reworking
  1859. #                        of the stata menu build procs.)
  1860. #                      "Help" added to Stata menu.  (Required splitting off
  1861. #                        "wwwCommandHelp" and "localCommandHelp" from
  1862. #                        command double-click, giving them optional arguments.
  1863. #                      Gave "doFile" an optional argument, so that it could
  1864. #                        be called from other code, or a shell.
  1865. #                      DblClick now looks for macro definitions in current file.
  1866. #                      "localHelpOnly" preference changed to "localHelp"
  1867. #                      Changing "localHelp" changes Stata Help menu bindings.
  1868. #                      Small fixes to SttaCompletions.tcl.
  1869. #                      Removed "codebookSuffix" preference, now that the 
  1870. #                        menu has "Mark File As…".
  1871. #                      Added "stataSig" preference to allow user to find
  1872. #                        local application if necessary.
  1873. #                      Added "Stta::sig" which returns Stata signature.
  1874. #  08/28/00 cbu 1.2.2  Added some of the flag preferences to "Stata Help" menu.
  1875. #                      Added "Stta::flagFlip" to change bullets in menu.
  1876. #                      Added a "noHelpKey" preference, which switches the
  1877. #                        "help" key binding to F8.
  1878. #                      Added "addNewCommands/Options" to "Stata Help" menu.
  1879. #                      Added "setStataApplication to "Stata Help" menu.
  1880. #  11/05/00 cbu 1.3    Added "next/prevCommand", "selectCommand", and
  1881. #                        "copyCommand" procs to menu.
  1882. #                      Added "continueComment" to menu.
  1883. #                      Added "Stta::indentLine".
  1884. #                      Added "reformatCommand" to menu.
  1885. #                      Modified "Stta::continueCommand" to take advantage of
  1886. #                        automatic indentation using Stta::indentLine.
  1887. #                      Modified Stta::programTemplate to take semi delimiter
  1888. #                        into account, and to not insert within a command.
  1889. #                      "Stta::reloadCompletions" is now obsolete.
  1890. #                      "Stta::updatePreferences" is now obsolete.
  1891. #                      "Stta::colorizeStta" now takes care of setting all 
  1892. #                        keyword lists, including Sttacmds.
  1893. #                      Cleaned up completion procs.  This file never has to be
  1894. #                        reloaded.  (Similar cleaning up for "Stta::DblClick").
  1895. #  11/16/00 cbu 2.0    New url prefs handling requires 7.4b21
  1896. #                      Added "Home Page" pref, menu item.
  1897. #                      Removed  hook::register requireOpenWindowsHook from
  1898. #                        mode declaration, put it after menu build.
  1899. #  12/19/00 cbu 2.1    The menu proc "Add Commands" now includes an option
  1900. #                        to grab all of the "extra" command from the current
  1901. #                        window, using Stta::addWindowCommands.
  1902. #                      Added "Keywords" submenu, "List Keywords" menu item.
  1903. #                      Big cleanup of ::sig, ::setApplication, processing ...
  1904. #  01/25/01 cbu 2.1.1  Bug fix for Stta::doSelection.
  1905. #                      Bug fix for comment characters.
  1906. #                      Better codebook marking.
  1907. #                      Added Stta::commandHelp for help file hyperlinks.
  1908.  
  1909. # ===========================================================================
  1910. # .
  1911.